//
//  smcJaikuAPI+messages.m
//  juhu
//
//  Created by Christian Martick on 26.07.07.
//  Copyright 2007 Christian Martick. All rights reserved.
//
//	jaiku api - recent posts of all jaiku users - public timeline sort of
//
//	this objects handle the users contacts posts using rss feed
//
//	Copyright (C) 2007 Christian Martick, http://juhu-mac.blogspot.com
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.

#import "smcJaikuAPI.h"

@implementation smcJaikuAPI (messages)

- (NSError *) postMessage: (NSString *) message withLocation: (NSString *) location andIcon: (int) index generated: (BOOL) flag
{
	// post a message to jaiku using rpc interface
	// connection is synchronously
	// returns nil if successful
	
	//check if _username and password are neq nil
	if ((_username == nil) || (_personalKey == nil))
		return [self missingUsernameOrPasswordErrorWithDomain: @"jaikuPostMessage"];
	
	//create dictionary for parameters 
	NSDictionary *theDict = [NSDictionary dictionaryWithObjectsAndKeys: 
		_username, @"user",
		_personalKey, @"personal_key",
		message, @"message",
		location, @"location",
		[NSNumber numberWithInt: index], @"icon", 
		[NSNumber numberWithBool: NO], @"generated",
		NULL];

	//url to jaiku xmlrpc
	NSURL *rpcURL = [NSURL URLWithString: @"http://api.jaiku.com/xmlrpc"];
	
	//create xml rpc request string
	XMLRPCRequest *xml = [[[XMLRPCRequest alloc] init] autorelease];
	[xml setMethodName: @"presence.send"];
	[xml setParameters: [NSArray arrayWithObject: theDict]];
	NSString *xmlstring = [xml requestText];
	
	//create http request
	NSMutableURLRequest *request = [NSMutableURLRequest 
		requestWithURL: rpcURL
		cachePolicy: NSURLRequestReloadIgnoringCacheData 
		timeoutInterval:15];
	[request addValue: JUHUCLIENT_VERSION forHTTPHeaderField: @"User-Agent"];
	[request setHTTPMethod: @"POST"];
	[request setValue: @"text/xml" forHTTPHeaderField:@"Content-Type"];
	[request setValue: [NSString stringWithFormat: @"%d", [xmlstring length]] forHTTPHeaderField: @"Content-Length"];
	
	[request setHTTPBody: [xmlstring dataUsingEncoding: NSUTF8StringEncoding]];
	
	//go for it
	NSError *error = nil;
	NSURLResponse *response = nil;
	
	NSData *responseData = [NSURLConnection sendSynchronousRequest: request
			returningResponse: &response
			error: &error];
	NSString *responseString = [[[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding] autorelease];
	
	// check if success
	// connection errors
	if ((error != nil) || (responseData == nil))
	{
		//something went wrong, set posted return error
		
		return [NSError errorWithDomain: @"jaikuPostMessage"
				code: kSmcErrorNoServerToPostTo 
				userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
					@"Could not post message", @"errorAbstract",
					@"Sorry, could not send the presence update.", @"errorText", NULL]];
	}
	
	// actual jaiku post failures, maybe key/username
	if ([responseString rangeOfString: @"<name>status</name><value><string>ok</string></value>"].location == NSNotFound)
	{
		// okay most likely 
		return [NSError errorWithDomain: @"jaikuPostMessage"
				code: kSmcErrorNoServerToPostTo 
				userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
					@"Could not post message", @"errorAbstract",
					@"Sorry, could not send the presence update, maybe your account credentials are wrong.", @"errorText", NULL]];
	}
	
	// okay, everthing fine
	return nil;
}

- (NSError *) postComment: (NSString *) comment to: (NSURL *) url
{
	// post a comment synchronously
	// this method isn't using rpc (since there is no api for that), but
	// rather using the html pages and a POST Request
	
	//check if _username and password are neq nil
	if ((_username == nil) || (_personalKey == nil))
		return [self missingUsernameOrPasswordErrorWithDomain: @"jaikuPostComment"];
	
	NSError *error;
	NSURLResponse *response;
	NSString *tmp;
	
	//strip off #...
	NSRange range = [[url absoluteString] rangeOfString: @"#"];
	if (range.location != NSNotFound)
		tmp = [NSString stringWithString: [[url absoluteString] substringToIndex: range.location]];
	else
		tmp = [NSString stringWithString: [url absoluteString]];

	//step one: get comment hash in order to be able to post
	NSURL *completeURL = [NSURL URLWithString: [NSString stringWithFormat: @"%@?user=%@&personal_key=%@", tmp, _username, _personalKey]];
	
	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: completeURL
			cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval:15];
	   
	[request addValue: JUHUCLIENT_VERSION forHTTPHeaderField: @"User-Agent"];
	
	NSData *data = [NSURLConnection sendSynchronousRequest: request
			returningResponse: &response
			error: &error];
			
	if ((data == nil) || (error != nil))
		return [NSError errorWithDomain: @"jaikuPostComment"
			code: kSmcErrorCommentNoHash 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not post comment", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the comment post failed", @"errorText", NULL]];
	
	NSString *page = [NSString stringWithString: [self makeCleanUTF8MutableStringFromData: data]];
	
	//well, data not really string? mh.
	if (page == nil)
		return [NSError errorWithDomain: @"jaikuPostComment" 
			code: kSmcErrorCommentNoPageString 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not post comment", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the comment post failed", @"errorText", NULL]];
	
	//find <input type="hidden" name="_nonce" value="??????" /> and get value!
	range = [page rangeOfString: @"<input type=\"hidden\" name=\"_nonce\" value=\""];

	//not found, well something went wrong!
	if (range.location == NSNotFound)
		return [NSError errorWithDomain: @"jaikuPostComment"
			code: kSmcErrorCommentNoHash 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not post comment", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the comment post failed", @"errorText", NULL]];

	NSMutableString *hash = [NSMutableString stringWithString: [page substringFromIndex: range.location + range.length]];
	
	range = [hash rangeOfString: @"\""];
	
	if (range.location == NSNotFound)
		return [NSError errorWithDomain: @"jaikuPostComment"
			code: kSmcErrorCommentNoHash 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not post comment", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the comment post failed", @"errorText", NULL]];
	
	[hash deleteCharactersInRange: NSMakeRange( range.location, [hash length] - range.location)];
		
	//clean comment
	NSString *toPost = [self urlEncodeValue: comment];
	
	//so with hash, put together post method...
	[request setHTTPMethod: @"POST"];
	[request setValue: @"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
	[request setValue: [NSString stringWithFormat: @"%d", [[NSString stringWithFormat: @"_nonce=%@&comment=%@", hash, toPost] length]]
		forHTTPHeaderField: @"Content-Length"];
	
	[request setHTTPBody: [[NSString stringWithFormat: @"_nonce=%@&comment=%@", hash, toPost] dataUsingEncoding: NSUTF8StringEncoding]];

	//post it
	[NSURLConnection sendSynchronousRequest: request
			returningResponse: &response
			error: &error];

	// finally the post didn't work out?
	if (error != nil)
		return [NSError errorWithDomain: @"jaikuPostComment"
			code: kSmcErrorCommentFailed
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not post comment", @"errorAbstract",
				@"The request to post a comment failed", @"errorText", 
				error, @"urlConnectionError", NULL]];
	else
		return nil;
}

- (BOOL) canDelete: (NSURL *) url
{
	// just make sure that it is not a channel post, but a comment or a normal presence post
	// if channel post return NO
	// also only real posts can be deleted, not aggregated feed stuff...
	// so again: this one doesn't check if you actually are the user belonging to the post,
	// it just looks into the format of the url!
	
	//is a jaiku entry, not an external feed? (jaiku.com should be in there somewhere)
	NSRange range = [[url absoluteString] rangeOfString: @"jaiku.com" options: NSBackwardsSearch range: NSMakeRange( 0, [[url absoluteString] length])];
	if (range.location == NSNotFound)
		return NO;
	
	//channel has channel in url, if not there, return YES
	range = [[url absoluteString] rangeOfString: @"/channel/" options: NSBackwardsSearch range: NSMakeRange( 0, [[url absoluteString] length])];
	if (range.location == NSNotFound)
		return YES;
	
	//okay it is a channel, but it could still be a comment!
	range = [[url absoluteString] rangeOfString: @"#c-" options: NSBackwardsSearch range: NSMakeRange( 0, [[url absoluteString] length])];
	
	if (range.location != NSNotFound)
		return YES;
		
	//nope - it is a plain channel post
	return NO;	
}

- (NSError *) deletePostOrCommentWithURL: (NSURL *) url
{
	//delete post at url synchronously
	// this method isn't using rpc (since there is no api for that), but
	// rather using the html pages and a POST Request
	
	/*	
		there three types to handle: basic post, comments, and channel entries
		
		basic posts: clean url (without #)
		comment: url with #c-??????, -> comment number
		post to a channel (not a comment to a channel) -> doesn't work right now
	*/
	
	//check if _username and password are neq nil
	if ((_username == nil) || (_personalKey == nil))
		return [self missingUsernameOrPasswordErrorWithDomain: @"jaikuDeleteMessage"];
	
	NSError *error = nil;
	NSURLResponse *response = nil;
	NSRange range;
	NSString *theURL;
	NSURL *completeURL;
	NSURL *deleteURL;
	NSString *searchFor;
	NSString *commentID;
	BOOL comment = NO;
	
	//step one: figure out if comment, post to channel or normal post
	range = [[url absoluteString] rangeOfString: @"#c-" options: NSBackwardsSearch range: NSMakeRange(0,[[url absoluteString] length])];
	
	if (range.location != NSNotFound)
	{
		//it is a comment!
		//get comment id
		commentID = [[url absoluteString] substringFromIndex: range.location + range.length];
		//shorten url
		theURL = [[url absoluteString] substringToIndex: range.location];
		//set search term
		searchFor = [NSString stringWithFormat: @"a href=\"?delete-comment=%@&_nonce=", commentID];
		//comment flag
		comment = YES;
	} else if ([[url absoluteString] rangeOfString: @"http://jaiku.com/channel/"].location != NSNotFound)
	{
		// maybe in the future
		//NSLog(@"channel delete post");
		return nil;
	}
	else
	{	
		//normal post
		//set url
		theURL = [url absoluteString];
		//set search term
		searchFor = @"a href=\"?delete=1&amp;_nonce=";
		//comment flag
		comment = NO;
	}
		
	//step 2: get hash 
	completeURL = [NSURL URLWithString: [NSString stringWithFormat: @"%@?user=%@&personal_key=%@", theURL, _username, _personalKey]];
		
	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: completeURL
			cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval:15];
	
	[request addValue: JUHUCLIENT_VERSION forHTTPHeaderField: @"User-Agent"];
		
	NSData *data = [NSURLConnection sendSynchronousRequest: request
			returningResponse: &response
			error: &error];
	
	if ((data == nil) || (error != nil))
		return [NSError errorWithDomain: @"jaikuDeleteMessage"
			code: kSmcErrorDeleteNoHash 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not delete entry", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the entry could not be deleted", @"errorText", NULL]];
		
	NSString *page = [NSString stringWithString: [self makeCleanUTF8MutableStringFromData: data]];
		
	//sometimes the data cannot be put into string (eg chinese or japanese chars, although utf 8)
	//well, data not really string? mh.
	if (page == nil)
		return [NSError errorWithDomain: @"jaikuDeleteMessage" 
			code: kSmcErrorDeleteNoPageString 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not delete entry", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the entry could not be deleted", @"errorText", NULL]];
				
	//find the search term and get _nonce
	range = [page rangeOfString: searchFor options: NSBackwardsSearch
		range: NSMakeRange(0,[page length])];
		
	//no hash found...
	if (range.location == NSNotFound)
		return [NSError errorWithDomain: @"jaikuDeleteMessage"
			code: kSmcErrorDeleteNoHash 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not delete entry", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the entry could not be deleted", @"errorText", NULL]];

	NSMutableString *hash = [NSMutableString stringWithString: [page substringFromIndex: range.location + range.length]];

	range = [hash rangeOfString: @"\""];

	//something wrong with the hash
	if (range.location == NSNotFound)
		return [NSError errorWithDomain: @"jaikuDeleteMessage"
			code: kSmcErrorDeleteNoHash 
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not delete entry", @"errorAbstract",
				@"Since the needed hash key could not be obtained, the entry could not be deleted", @"errorText", NULL]];
		
	[hash deleteCharactersInRange: NSMakeRange( range.location, [hash length] - range.location)];
	
	//step 3: finally put it all together
	if (comment)
		deleteURL = [NSURL URLWithString: [NSString stringWithFormat: @"%@&delete-comment=%@&really=1&_nonce=%@", [completeURL absoluteString], commentID, hash]];
	else
		deleteURL = [NSURL URLWithString: [NSString stringWithFormat: @"%@&delete=1&really=1&_nonce=%@", [completeURL absoluteString], hash]];
		
	//and go for it
	request = [NSMutableURLRequest requestWithURL: deleteURL
			cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval:15];
		   
	[request addValue: JUHUCLIENT_VERSION forHTTPHeaderField: @"User-Agent"];
		
	[NSURLConnection sendSynchronousRequest: request
			returningResponse: &response
			error: &error];
		
	//now the last thing that can go wrong...
	if (error != nil)
		return [NSError errorWithDomain: @"jaikuPostComment"
			code: kSmcErrorDeleteFailed
			userInfo: [NSDictionary dictionaryWithObjectsAndKeys: 
				@"Could not delete entry", @"errorAbstract",
				@"The request to delete an entry failed", @"errorText", 
				error, @"urlConnectionError", NULL]];
	else
		return nil;
}

@end
